home *** CD-ROM | disk | FTP | other *** search
Oberon Text | 1996-01-25 | 24.6 KB | 688 lines | [TEXT/.Ob4] |
- Syntax10.Scn.Fnt
- InfoElems
- Alloc
- Syntax10.Scn.Fnt
- StampElems
- Alloc
- 25 Jan 96
- "Title": Kernel.Mod
- "Author": mmb 8.5.91 / 13.10.93 / RC 28.10.91 / HM 27.6.94 / mah 16.12.94
- "From": 10.02.95 12:30:34
- "Until":
- "Changes":
- 10.2.95 mah ptrs <= 0 not marked anymore instead of ptr = 0 as previously
- 17.2.95 mah best fit instead of first fit when allocating a big block
- 27.6.95 mk finalization, queues are now stacks, prepare Queue added
- 29.11.95 mah CheckCandidates: fix to avoid marking of free blocks
- 30.11.95 mah CHeckCandidates: ptr into block -> block not freed (e.g. VAR-Par p.x on stack. p = NIL)
- Syntax10b.Scn.Fnt
- Syntax10i.Scn.Fnt
- FoldElems
- Syntax10.Scn.Fnt
- IF (heapSize > minHeapSize) & (lastSize >= minHeapExt) THEN (*<<*)
- lastSize := ShrinkHeap(lastSize)
- END;
- Syntax10.Scn.Fnt
- VAR p: FreeBlock; i, size: LONGINT;
- BEGIN
- p := S.VAL(FreeBlock, lastBlock);
- IF p # NIL THEN DEC(requiredSize, p.size + 4) END;
- size := S.VAL(LONGINT, S.VAL(SET, requiredSize+(minHeapExt-1)) - S.VAL(SET, minHeapExt-1));
- Sys.SetPtrSize(heapAdr, heapSize + size);
- IF Sys.MemError() # 0 THEN Sys.Str("Heap overflow$"); HALT(20) END;
- requiredSize := size;
- IF p # NIL THEN
- i := p.size + 4; INC(size, i);
- i := Min(i DIV B, N);
- A[i] := p.next
- ELSE p := S.VAL(FreeBlock, heapEnd)
- END;
- p.tag := S.VAL(Tag, S.ADR(p.size)); p.size := size - 4;
- p.next := A[N]; A[N] := p;
- INC(heapSize, requiredSize); INC(heapEnd, requiredSize)
- END ExpandHeap;
- Syntax10.Scn.Fnt
- VAR shrink, newSize: LONGINT;
- BEGIN
- shrink := S.VAL(LONGINT, S.VAL(SET, lastSize) - S.VAL(SET, minHeapExt-1));
- newSize := heapSize - shrink;
- IF newSize < minHeapSize THEN newSize := minHeapSize; shrink := heapSize - minHeapSize END;
- Sys.SetPtrSize(heapAdr, newSize);
- IF Sys.MemError() # 0 THEN RETURN lastSize
- ELSE DEC(heapSize, shrink); DEC(heapEnd, shrink); RETURN lastSize - shrink
- END
- END ShrinkHeap;
- Syntax10.Scn.Fnt
- VAR tag, supertag, x, y: LONGINT; typename: ARRAY 32 OF CHAR; m: Modules.Module;
- BEGIN
- x := p-4;
- REPEAT INC(x, 4); S.GET(x, y) UNTIL y < 0;
- tag := x + y;
- S.GET(tag-4, supertag);
- supertag := S.VAL(LONGINT, S.VAL(SET, supertag) - mark);
- S.MOVE(supertag+16, S.ADR(typename), 32);
- IF (typename # "ObjDesc") & (typename # "StrDesc") & (typename # "NodeDesc") THEN
- S.GET(supertag+48, m);
- Modules.Print(m.name, 0); Modules.Print(". ", 0);
- Modules.Print(typename, 0); Modules.Print(", n = %d$", (p-tag-4) DIV 4)
- END
- END PrintType;
- MODULE Kernel; (* mmb 8.5.91 / 13.10.93 / RC 28.10.91 / HM 27.6.94 / mah 16.12.94 *)
- (* Finalization due to J.Templ implemented by MK 22.2.95 *)
- (* memory management and trap handling for PowerMac Oberon *)
- (* WARNING: do not use NEW nor SYSTEM.NEW in this module !! use NewRec, NewArr or NewSys instead *)
- IMPORT S := SYSTEM, Modules, Sys;
- CONST
- MarkBit* = 31; ArrayBit = 30; RecBit = 30;
- B = 16; (*chunk size: memory blocks are allocated in multiples of B bytes*)
- N = 9; (*number of free lists*)
- mark = {MarkBit}; array = {ArrayBit};
- TYPE
- Tag = POINTER TO TypeDesc;
- TypeDesc = RECORD
- size: LONGINT;
- ptroff: LONGINT
- END;
- FreeBlock = POINTER TO FreeBlockDesc;
- FreeBlockDesc = RECORD
- tag: Tag;
- size: LONGINT; (*size of block without tag*)
- next: FreeBlock;
- filler: LONGINT;
- firstofnext: LONGINT
- END;
- Block* = POINTER TO BlockDesc;
- BlockDesc = RECORD
- last, cur, first: Block (*fields of open array descriptor*)
- END;
- Blockm4 = POINTER TO Blockm4Desc;
- Blockm4Desc = RECORD
- tag: Tag;
- last, cur, first: LONGINT;
- filler0, filler1, filler2, filler3, firstofnext: LONGINT
- END;
- Stack = POINTER TO StackDesc;
- StackDesc = RECORD
- beg, end: LONGINT;
- next: Stack
- END;
- Notifier* = PROCEDURE;
- Queue* = RECORD
- notify: ARRAY 8 OF Notifier
- END;
- Finalizer* = PROCEDURE (obj: S.PTR);
- FinObj = POINTER TO FinObjNode;
- FinObjNode = RECORD
- next: FinObj;
- obj: LONGINT;
- marked: BOOLEAN;
- fin: Finalizer
- END;
- heapBeg*, heapEnd*: LONGINT; (*borders of used heap (B aligned - 4)*)
- resumeSP*: LONGINT; (*SP of Oberon.Loop*)
- GCenabled*: BOOLEAN;
- prepQ*, quitQ*, gcQ*, afterQ*: Queue; (* prep queue called before GC, gc queue during GC *)
- finalize: BOOLEAN; (* flag to avoid finalization in the case: Finalizer starts GC MK *)
- heapAdr, heapSize: LONGINT; (*actual heap address and size*)
- resumePC, resumeFP: LONGINT; (*resume execution after trap here*)
- A: ARRAY N+1 OF FreeBlock; (*free lists*)
- PointerTD, stackTD: ARRAY 4 OF LONGINT;
- firstStack, curStack: Stack;
- firstTry, checkStack: BOOLEAN;
- nofcand: INTEGER;
- finObjs*: FinObj; (* list of objects to be finalized *)
- PROCEDURE^ NewBlock (size: LONGINT): FreeBlock;
- PROCEDURE^ NewRec (tg: LONGINT): LONGINT;
- PROCEDURE^ NewSys (size: LONGINT): LONGINT;
- PROCEDURE^ NewArr (eltg, nofelem, nofdim: LONGINT): LONGINT;
- PROCEDURE^ Mark* (block: Block);
- PROCEDURE Min (x, y: LONGINT): LONGINT;
- BEGIN
- IF x < y THEN RETURN x ELSE RETURN y END
- END Min;
- (* --- queues --- *)
- PROCEDURE (VAR q: Queue) Init*;
- VAR i: INTEGER;
- BEGIN
- FOR i := 0 TO LEN(q.notify)-1 DO q.notify[i] := NIL END
- END Init;
- PROCEDURE (VAR q: Queue) Add* (notify: Notifier);
- VAR i: INTEGER;
- BEGIN
- FOR i := 0 TO LEN(q.notify)-1 DO
- IF q.notify[i] = NIL THEN q.notify[i] := notify; RETURN END
- END
- END Add;
- PROCEDURE (VAR q: Queue) Remove* (notify: Notifier);
- VAR i: INTEGER;
- BEGIN
- FOR i := 0 TO LEN(q.notify)-1 DO
- IF q.notify[i] = notify THEN q.notify[i] := NIL; RETURN END
- END
- END Remove;
- PROCEDURE (VAR q: Queue) Handle*;
- VAR i: INTEGER;
- BEGIN
- FOR i := LEN(q.notify)-1 TO 0 BY - 1 DO
- IF q.notify[i] # NIL THEN q.notify[i] END
- END
- END Handle;
- (* --- finalization --- *)
- PROCEDURE RegisterObject* (obj: S.PTR; fin: Finalizer);
- VAR n, n1: FinObj;
- PROCEDURE new (VAR o: S.PTR);
- VAR adr: LONGINT;
- BEGIN
- adr := NewRec (S.VAL (LONGINT, o));
- S.PUT (S.ADR (o), adr);
- END new;
- BEGIN
- new (n); n.obj := S.VAL (LONGINT, obj); n.marked := TRUE; n.fin := fin; n.next := NIL;
- IF finObjs = NIL THEN finObjs :=n
- ELSE
- n1 := finObjs;
- WHILE n1.next # NIL DO n1 := n1.next END;
- n1.next := n
- END
- END RegisterObject;
- PROCEDURE FinalizeObjs;
- VAR n, prev: FinObj;
- BEGIN
- IF finalize THEN RETURN END;
- finalize := TRUE;
- n := finObjs; prev := NIL;
- WHILE n # NIL DO
- IF ~ n.marked THEN
- n.fin (S.VAL (S.PTR, n.obj));
- IF n = finObjs THEN finObjs := finObjs.next ELSE prev.next := n.next END;
- ELSE prev := n
- END;
- n := n.next
- END;
- finalize := FALSE;
- END FinalizeObjs;
- PROCEDURE FinalizeAll*;
- VAR n, prev: FinObj;
- BEGIN
- finalize := TRUE;
- n := finObjs;
- WHILE n # NIL DO n.fin (S.VAL (S.PTR, n.obj)); n := n.next END
- END FinalizeAll;
- PROCEDURE CheckFinObjs;
- VAR n: FinObj; tag: LONGINT;
- BEGIN
- n := finObjs;
- WHILE n # NIL DO
- S.GET (n.obj - 4, tag);
- n.marked := MarkBit IN S.VAL (SET, tag);
- n := n.next
- END;
- (* marks all objects accessible from not marked n.obj s to prevent them from being collected *)
- n := finObjs;
- WHILE n # NIL DO
- S.GET (n.obj - 4, tag);
- IF ~n.marked THEN Mark (S.VAL (Block, n.obj)) END;
- n := n.next
- END;
- END CheckFinObjs;
- (* --- memory management --- *)
- PROCEDURE AllocateHeap;
- VAR grow: LONGINT;
- BEGIN
- Sys.MaxApplZone;
- heapSize := Sys.MaxMem(grow) - 1000*1024;
- heapAdr := Sys.NewPtr(heapSize);
- IF heapAdr <= 0 THEN Modules.Print("-- could not allocate heap$", 0) END;
- END AllocateHeap;
- PROCEDURE Available* (): LONGINT;
- VAR i, avail: LONGINT; p: FreeBlock;
- BEGIN
- avail := 0;
- FOR i := 0 TO N DO
- p := A[i];
- WHILE p # NIL DO INC(avail, p.size+4); p := p.next END
- END;
- RETURN avail
- END Available;
- PROCEDURE LargestAvailable* (): LONGINT;
- VAR i, max: LONGINT; p: FreeBlock;
- BEGIN
- i := N; max := 0;
- WHILE (i >= 0) & (max = 0) DO
- p := A[i];
- WHILE p # NIL DO
- IF p.size > max THEN max := p.size END;
- p := p.next
- END;
- DEC(i)
- END;
- RETURN max + 4
- END LargestAvailable;
- PROCEDURE RemoveStack* (pos: LONGINT);
- VAR s, last: Stack;
- BEGIN
- s := firstStack;
- WHILE (s # NIL) & ((pos < s.beg) OR (pos > s.end)) DO last := s; s := s.next END;
- IF (s # NIL) & (s # curStack) THEN
- IF s = firstStack THEN firstStack := s.next ELSE last.next := s.next END
- END
- END RemoveStack;
- PROCEDURE AddStack* (beg, end: LONGINT);
- VAR s: Stack;
- BEGIN
- RemoveStack(beg);
- s :=S.VAL(Stack, NewRec(S.ADR(stackTD)+4)) ; s.beg := beg; s.end := end; s.next := firstStack; firstStack := s
- END AddStack;
- PROCEDURE MarkStack*;
- VAR SP: LONGINT;
- BEGIN
- S.GETREG(1, SP); S.GET(SP, curStack.end)
- END MarkStack;
- PROCEDURE Mark* (block: Block);
- TYPE
- Tag0 = POINTER TO RECORD
- (*size: LONGINT; skipped, because accessed via tag = actual tag + 4*)
- ptroff: LONGINT
- END;
- VAR cur, prev, p: Block; offset, adr, tdadr: LONGINT; tag, downtag, marked: Tag0; arraybit, set: SET;
- BEGIN
- S.GET(S.VAL(LONGINT, block)-4, tag);
- marked := S.VAL(Tag0, S.VAL(SET, tag) + mark);
- IF tag # marked THEN
- (*---- mark type descriptor*)
- tdadr := S.VAL(LONGINT, S.VAL(SET, tag) - array) - 4;
- S.GET (tdadr, set);
- IF RecBit IN set THEN tdadr := S.VAL(LONGINT, set - {RecBit, MarkBit}) - 4; S.GET(tdadr, set) END;
- S.PUT(tdadr, set + mark);
- (*---- mark object*)
- S.PUT(S.VAL(LONGINT, block)-4, marked);
- arraybit := S.VAL(SET, tag) * array;
- IF arraybit # {} THEN
- cur := block.first;
- tag := S.VAL(Tag0, S.VAL(SET, tag) - arraybit)
- ELSE cur := block
- END;
- prev := NIL;
- LOOP
- INC(S.VAL(LONGINT, tag), 4);
- offset := tag.ptroff;
- IF offset < 0 THEN (*up*)
- INC(S.VAL(LONGINT, tag), offset);
- IF (arraybit # {}) & (cur # block.last) THEN
- INC(S.VAL(LONGINT, cur), tag.ptroff) (* INC(cur, recsize) *)
- ELSE (* up *)
- S.PUT(S.VAL(LONGINT, block)-4, S.VAL(SET, tag) + arraybit + mark);
- IF prev = NIL THEN EXIT END;
- S.GET(S.VAL(LONGINT, prev)-4, tag);
- arraybit := S.VAL(SET, tag) * array;
- tag := S.VAL(Tag0, S.VAL(SET, tag) - array - mark);
- IF arraybit # {} THEN cur := prev.cur ELSE cur := prev END;
- adr := S.VAL(LONGINT, cur) + tag.ptroff;
- S.GET(adr, p);
- S.PUT(adr, block);
- block := prev;
- prev := p
- END
- ELSE (*down*)
- adr := S.VAL(LONGINT, cur) + offset;
- S.GET(adr, p);
- IF S.VAL (LONGINT, p) > 0 THEN
- S.GET(S.VAL(LONGINT, p)-4, downtag);
- marked := S.VAL(Tag0, S.VAL(SET, downtag) + mark);
- IF downtag # marked THEN
- (*---- mark type descriptor*)
- tdadr := S.VAL(LONGINT, S.VAL(SET, downtag) - array) - 4;
- S.GET (tdadr, set);
- IF RecBit IN set THEN tdadr := S.VAL(LONGINT, set - {RecBit, MarkBit}) - 4; S.GET(tdadr, set) END;
- S.PUT(tdadr, set + mark);
- (*---- mark object*)
- S.PUT(S.VAL(LONGINT, p)-4, marked);
- S.PUT(S.VAL(LONGINT, block)-4, S.VAL(SET, tag) + arraybit + mark);
- IF arraybit # {} THEN block.cur:= cur END;
- arraybit := S.VAL(SET, downtag) * array;
- IF arraybit # {} THEN cur := p.first ELSE cur := p END;
- tag := S.VAL(Tag0, S.VAL(SET, downtag) - arraybit);
- S.PUT(adr, prev);
- prev := block;
- block := p
- END
- END
- END
- END
- END
- END Mark;
- PROCEDURE Sweep;
- VAR p, end: Blockm4; free: FreeBlock; tag, unmarked, tdesc: Tag; size, lastSize, i: LONGINT;
- last: ARRAY N+1 OF FreeBlock;
- BEGIN
- FOR i :=0 TO N DO A[i] := NIL END;
- (*-- sweep through all blocks*)
- p := S.VAL(Blockm4, heapBeg);
- end := S.VAL(Blockm4, heapEnd);
- lastSize := 0;
- WHILE p # end DO
- tag := p.tag;
- unmarked := S.VAL(Tag, S.VAL(SET, tag) - mark);
- tdesc := S.VAL(Tag, S.VAL(SET, unmarked) - array);
- IF unmarked # tdesc THEN (*array block*)
- size := p.last + tdesc.size - S.VAL(LONGINT, p)
- ELSE size := tdesc.size + 4
- END;
- size := S.VAL(LONGINT, S.VAL(SET, size + B-1) - S.VAL(SET, B-1));
- IF tag = unmarked THEN (*collect*)
- Modules.Print ("Size = %d$", size);
- IF lastSize = 0 THEN free := S.VAL(FreeBlock, p) END;
- INC(lastSize, size)
- ELSE
- p.tag := unmarked;
- IF lastSize > 0 THEN (*add last free block to free list*)
- Modules.Print ("Merged = %d$", lastSize);
- free.size := lastSize - 4;
- free.tag := S.VAL(Tag, S.ADR(free.size));
- i := Min(lastSize DIV B, N);
- IF A[i] = NIL THEN A[i] := free ELSE last[i].next := free END;
- last[i] := free; free.next := NIL; lastSize := 0
- END
- END;
- INC(S.VAL(LONGINT, p), size)
- END;
- shrink heap
- (*-- add last free block to free list*)
- IF lastSize > 0 THEN
- Modules.Print ("Merged = %d$", lastSize);
- free.size := lastSize - 4;
- free.tag := S.VAL(Tag, S.ADR(free.size));
- i := Min(lastSize DIV B, N);
- IF A[i] = NIL THEN A[i] := free ELSE last[i].next := free END;
- last[i] := free; free.next := NIL
- END
- END Sweep;
- PROCEDURE CheckCandidates (candidates: ARRAY OF LONGINT); (*nofcand > 0*)
- VAR h, i, j, size, cand, block, last, heapEnd0, prevBlock: LONGINT; tag, unmarked, tdesc: Tag;
- BEGIN
- (*-- sort candidates in increasing order using shellsort *)
- h := 1; REPEAT h := h*3 + 1 UNTIL h > nofcand;
- REPEAT h := h DIV 3; i := h;
- WHILE i < nofcand DO cand := candidates[i]; j := i;
- WHILE (j >= h) & (candidates[j-h] > cand) DO
- candidates[j] := candidates[j-h]; j := j-h;
- END;
- candidates[j] := cand; INC(i)
- END
- UNTIL h = 1;
- (*-- sweep*)
- block := heapBeg + 4; heapEnd0 := heapEnd + 4;
- i := 0; cand := candidates[i];
- prevBlock := block;
- LOOP
- IF cand <= block THEN
- IF cand = block THEN
- S.GET(cand-4, h);
- IF h # cand THEN Mark(S.VAL(Block, block)) END (* else it is a free block *)
- ELSE (* cand < block => ptr into a block (e.g. VAR-Par p.x) *)
- S.GET(prevBlock-4, h);
- IF h # prevBlock THEN Mark(S.VAL(Block, prevBlock)) END; (* else it is a free block *)
- END;
- INC(i);
- IF i = nofcand THEN EXIT END;
- cand := candidates[i]
- ELSE (*cand > block*)
- S.GET(block-4, tag);
- unmarked := S.VAL(Tag, S.VAL(SET, tag) - mark);
- tdesc := S.VAL(Tag, S.VAL(SET, unmarked) - array);
- IF tdesc # unmarked THEN (*array block*) S.GET(block, last); size := last + tdesc.size - block + 4
- ELSE size := tdesc.size + 4
- END;
- prevBlock := block;
- INC(block, S.VAL(LONGINT, S.VAL(SET, size + B-1) - S.VAL(SET, B-1)));
- IF block = heapEnd0 THEN EXIT END
- END
- END
- END CheckCandidates;
- PROCEDURE Candidate (VAR cand: ARRAY OF LONGINT; p: LONGINT);
- VAR tag: LONGINT;
- BEGIN
- IF (*(p MOD B = 0) &*) (p >= heapBeg) & (p < heapEnd) THEN
- (* ptr into a block possible as well -> less criterias
- S.GET(p-4, tag);
- IF ~ODD(tag) (*unmarked*) THEN
- candidates[nofcand] := p; INC(nofcand);
- IF nofcand = LEN(candidates) THEN CheckCandidates; nofcand := 0 END
- END
- cand[nofcand] := p; INC(nofcand);
- IF nofcand = LEN(cand) THEN CheckCandidates (cand); nofcand := 0 END
- END
- END Candidate;
- PROCEDURE SetMark (adr: LONGINT);
- VAR set: SET;
- BEGIN
- S.GET (adr - 4, set); set := set + mark; S.PUT (adr - 4, set)
- END SetMark;
- PROCEDURE CheckMark (adr: LONGINT);
- VAR set: SET;
- BEGIN
- S.GET (adr - 4, set);
- IF MarkBit IN set THEN Modules.Print ("Check: %x", S.VAL (LONGINT, set)); Modules.Print (", %x$", adr) END;
- END CheckMark;
- PROCEDURE GC*;
- VAR m: Modules.Module; i, data, offset, beg, p: LONGINT; ptr: Block; s: Stack; set: SET; cand: ARRAY 1024 OF LONGINT;
- BEGIN
- IF GCenabled THEN
- prepQ.Handle;
- FOR i := 0 TO N DO A[i] := NIL END;
- m := Modules.modules;
- WHILE m # NIL DO
- SetMark (S.VAL(LONGINT, m)); SetMark (m.block- 4);
- data := m.SB;
- FOR i := 0 TO m.nofptrs - 1 DO
- S.GET(m.pointers + 4*i, offset);
- S.GET(data + offset, ptr);
- IF S.VAL (LONGINT, ptr) > 0 THEN Mark(ptr) END
- END;
- FOR i := 0 TO m.noftds - 1 DO
- S.GET (m.typedescs + 4*i, p);
- S.GET (p-4, set);
- p := S.VAL(LONGINT, set - {RecBit, MarkBit});
- IF RecBit IN set THEN SetMark(p) END
- END;
- m := m.link
- END;
- IF checkStack THEN
- MarkStack;
- s := firstStack; nofcand := 0;
- WHILE s # NIL DO
- i := s.end; beg := s.beg;
- WHILE i < beg DO
- S.GET(i, p);
- Candidate (cand, p);
- INC(i, 4)
- END;
- s := s.next
- END;
- (*-- callee-saved general registers *)
- S.GETREG(13, p); Candidate(cand, p);
- S.GETREG(14, p); Candidate(cand, p);
- S.GETREG(15, p); Candidate(cand, p);
- S.GETREG(16, p); Candidate(cand, p);
- S.GETREG(17, p); Candidate(cand, p);
- S.GETREG(18, p); Candidate(cand, p);
- S.GETREG(19, p); Candidate(cand, p);
- S.GETREG(20, p); Candidate(cand, p);
- S.GETREG(21, p); Candidate(cand, p);
- S.GETREG(22, p); Candidate(cand, p);
- S.GETREG(23, p); Candidate(cand, p);
- S.GETREG(24, p); Candidate(cand, p);
- S.GETREG(25, p); Candidate(cand, p);
- S.GETREG(26, p); Candidate(cand, p);
- S.GETREG(27, p); Candidate(cand, p);
- S.GETREG(28, p); Candidate(cand, p);
- S.GETREG(29, p); Candidate(cand, p);
- S.GETREG(30, p); Candidate(cand, p);
- IF nofcand > 0 THEN CheckCandidates (cand) END
- END;
- CheckFinObjs; (* finalization MK *)
- gcQ.Handle;
- Sweep;
- m:= Modules.modules;
- WHILE m # NIL DO
- (* CheckMark (S.VAL(LONGINT, m)); CheckMark (m.block-4);*)
- FOR i := 0 TO m.noftds - 1 DO
- S.GET (m.typedescs + 4*i, p);
- S.GET (p-4, set);
- p := S.VAL(LONGINT, set - {RecBit, MarkBit});
- (* IF RecBit IN set THEN CheckMark(p) END*)
- END;
- m := m.link
- END;
- FinalizeObjs; (* finalization MK *)
- afterQ.Handle
- END
- END GC;
- PROCEDURE NewBlock (size: LONGINT): FreeBlock; (* size MOD B = 0 *)
- VAR i, rest: LONGINT; p, q, lp, lq: FreeBlock;
- BEGIN
- i := Min(size DIV B, N);
- WHILE (i < N) & (A[i] = NIL) DO INC(i) END;
- IF i = N THEN
- lp := A[i];
- WHILE lp # NIL DO (* 17.2.85 mah *)
- IF lp.size + 4 >= size THEN
- IF (p = NIL) OR (p.size > lp.size) THEN p := lp; q := lq END
- END;
- lq := lp; lp := lp.next
- END;
- IF p = NIL THEN
- IF firstTry THEN
- GC;
- firstTry := FALSE; p := NewBlock(size); firstTry := TRUE;
- RETURN p
- ELSE
- Modules.Print("--- heap overflow$", 0); HALT(20)
- END
- ELSIF q # NIL THEN q.next := p.next
- ELSE A[N] := p.next
- END
- ELSE (*p # NIL *) p := A[i]; A[i] := p.next
- END;
- rest := p.size + 4 - size;
- IF rest > 0 THEN
- IF size > 10 * 1024 THEN
- q := p;
- p := S.VAL(FreeBlock, S.VAL(LONGINT, p) + rest)
- ELSE
- q := S.VAL(FreeBlock, S.VAL(LONGINT, p) + size)
- END;
- q.tag := S.VAL(Tag, S.ADR(q.size));
- q.size := rest - 4;
- i := Min(rest DIV B, N); q.next := A[i]; A[i] := q
- END;
- RETURN p
- END NewBlock;
- PROCEDURE NewRec (tg: LONGINT): LONGINT; (* implementation of NEW(p) *)
- VAR size, null: LONGINT; p, q: FreeBlock; tag: Tag; BEGIN (* tag.size = rectyp.size *)
- tag := S.VAL(Tag, tg);
- size := S.VAL(LONGINT, S.VAL(SET, tag.size + 4 (*tag*) + B-1) - S.VAL(SET, B-1));
- p := NewBlock(size);
- (*-- the following code is optimized for RISC processors*)
- q := S.VAL(FreeBlock, S.VAL(LONGINT, p) + size - B);
- null := 0;
- q.size := null; q.next := S.VAL(FreeBlock, null); q.filler := null;
- WHILE q # p DO
- DEC(S.VAL(LONGINT, q), B);
- q.size := null; q.next := S.VAL(FreeBlock, null); q.filler := null; q.firstofnext := null (* q.firstofnext is in next block *)
- END;
- p.tag := tag;
- RETURN S.VAL(LONGINT, p) + 4
- END NewRec;
- PROCEDURE NewSys (size: LONGINT): LONGINT; (* implementation of S.NEW(p, size) *)
- VAR p, q: FreeBlock; null: LONGINT;
- BEGIN (* mah: v 12 statt 8 to allow NEW (string, 4) to work correctly *)
- size := S.VAL(LONGINT, S.VAL(SET, size + (4 (*tag*) + 12 (*dummyTD*) + B-1)) - S.VAL(SET, B-1));
- p := NewBlock(size);
- (*-- set up dummyTD at the end of the block in order to treat system blocks like unmarked blocks*)
- q := S.VAL(FreeBlock, S.VAL(LONGINT, p) + size - B);
- p.tag := S.VAL(Tag, S.ADR(q.next));
- q.size := 0; q.next := S.VAL(FreeBlock, size - 4); q.filler := -4;
- (*-- the following code is optimized for RISC processors*)
- null := 0;
- WHILE q # p DO
- DEC(S.VAL(LONGINT, q), B);
- q.size := null; q.next := S.VAL(FreeBlock, null); q.filler := null; q.firstofnext := null (* q.firstofnext is in next block *)
- END;
- RETURN S.VAL(LONGINT, p) + 4
- END NewSys;
- PROCEDURE NewArr (eltg, nofelem, nofdim: LONGINT): LONGINT; (* implementation of NEW(p, dim0, dim1, ...) *)
- VAR size, first, elSize, arrSize, vectSize, null: LONGINT; p, q: Blockm4; eltag: Tag;
- BEGIN
- eltag := S.VAL(Tag, eltg);
- IF eltag = NIL THEN (*ARRAY OF POINTER*) eltag := S.VAL(Tag, S.ADR(PointerTD[1])) END;
- elSize := eltag.size;
- arrSize := nofelem*elSize;
- vectSize := 8*(nofdim DIV 2) + 4; (* -> ADR(first) MOD 8 = 0 *)
- IF eltag.ptroff = -4 THEN (*no pointers in element type*) RETURN NewSys(arrSize + vectSize + 12) END;
- size := S.VAL(LONGINT, S.VAL(SET, arrSize + vectSize + (16 + B-1))-S.VAL(SET, B-1));
- p := S.VAL(Blockm4, NewBlock(size));
- q := S.VAL(Blockm4, S.VAL(LONGINT, p) + size - 2*B);
- (*-- the following code is optimized for RISC processors*)
- null := 0;
- q.filler1 := null; q.filler2 := null; q.filler3 := null;
- WHILE q # p DO
- DEC(S.VAL(LONGINT, q), B);
- q.filler1 := null; q.filler2 := null; q.filler3 := null; q.firstofnext := null (* q.firstofnext is in next block *)
- END;
- p.tag := S.VAL(Tag, S.VAL(SET, eltag) + array);
- first := S.ADR(p.first) + 4 + vectSize;
- p.last := first + arrSize - elSize;
- (*p.cur is reserved for Mark phase*)
- p.first := first;
- p.filler0 := null;
- RETURN S.VAL(LONGINT, p) + 4
- END NewArr;
- (* --- trap handling --- *)
- PROCEDURE MarkState*; (*called at the very beginning of Oberon.Loop*)
- VAR SP: LONGINT;
- BEGIN
- S.GETREG(1, SP); S.GET(SP, resumeSP); S.GET (resumeSP-4, resumeFP); S.GETREG(40 (*LR*), resumePC);
- curStack := S.VAL(Stack, NewRec(S.ADR(stackTD)+4)); curStack.beg := resumeSP; curStack.next := NIL;
- firstStack := curStack
- END MarkState;
- PROCEDURE Resume* (context: Sys.ExceptionInfo);
- BEGIN
- context.reg.R[31*2+1] := resumeFP;
- context.spec.PC := resumePC;
- END Resume;
- (* --- initialization --- *)
- PROCEDURE Init;
- VAR a: LONGINT; size, i: LONGINT; p: FreeBlock;
- BEGIN
- firstTry := TRUE; GCenabled := TRUE; checkStack := TRUE;
- Modules.NewRec := NewRec; Modules.NewSys := NewSys; Modules.NewArr := NewArr;
- PointerTD[0] := S.VAL(LONGINT, mark); (*marked*)
- PointerTD[1] := 4; (*pointer size*)
- PointerTD[2] := 0; (*pointer offset in element*)
- PointerTD[3] := -8; (*sentinel*)
- stackTD[0] := S.VAL(LONGINT, mark);
- stackTD[1] := 12; (*size*)
- stackTD[2] := 8; (*offset of next*)
- stackTD[3] := -8; (*sentinel*)
- quitQ.Init; gcQ.Init; prepQ.Init; afterQ.Init;
- finObjs := NIL; finalize := FALSE; (* finalization MK *)
- (*-- allocate heap; adjust to multiple of B minus 4*)
- AllocateHeap;
- heapBeg := heapAdr + ((-heapAdr-4) MOD B); (*B aligned - 4*)
- size := heapAdr + heapSize - heapBeg;
- DEC(size, size MOD B);
- heapEnd := heapBeg + size; (*B aligned - 4*)
- (*-- make the whole heap a single free block*)
- p := S.VAL(FreeBlock, heapBeg);
- p.tag := S.VAL(Tag, S.ADR(p.size)); p.size := size - 4; p.next := NIL;
- A[N] := p;
- FOR i := 0 TO N-1 DO A[i] := NIL END;
- END Init;
- BEGIN
- Init
- END Kernel.
- PROCEDURE ExpandHeap (requiredSize: LONGINT);
- PROCEDURE ShrinkHeap (lastSize: LONGINT): LONGINT;
- PROCEDURE PrintType (p: LONGINT);
-